using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using SudokuHelper.Appearance;
using SudokuHelper.Controllers;
using SudokuHelper.Model.Values;

namespace SudokuHelper.Views {
    public partial class SudokuView : UserControl, ISudokuView {
        #region Private members

        private CellAppearance defaultApp,
                               selectedApp,
                               errorApp;

        private ICellView selectedCell, errorCell;
        private readonly ICellView[,] cells = new ICellView[9,9];

        private ISudokuController controller;

        #endregion

        #region Public members

        [Category("Appearance")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [TypeConverter(typeof(ExpandableObjectConverter))]
        public CellAppearance AppearanceDefault {
            get { return defaultApp;}
        }

        [Category("Appearance")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [TypeConverter(typeof(ExpandableObjectConverter))]
        public CellAppearance AppearanceSelected {
            get { return selectedApp; }
        }

        [Category("Appearance")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [TypeConverter(typeof(ExpandableObjectConverter))]
        public CellAppearance AppearanceError {
            get { return errorApp; }
        }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public ISudokuController Controller {
            set {
                controller = value;
                controller.View = this;
                BuildView();
            }
        }

        #endregion
        
        #region Constructors

        public SudokuView() {
            InitializeComponent();

            defaultApp = new CellAppearance(Color.Linen, Color.Black, Color.Blue);
            selectedApp = new CellAppearance(Color.SeaGreen, Color.WhiteSmoke, Color.Blue);
            errorApp = new CellAppearance(Color.Red, Color.White, Color.Red);
        }

        #endregion

        #region Utility methods

        public void Reset() {
        }

        private void BuildView() {
            for (int i = 0; i < 9; i++){
                for (int j = 0; j < 9; j++){
                    var cell = new CellView(i,j)
                                   {
                                       Location = new Point(5 + i*52, 5+j*52),
                                       Size = new Size(50,50),
                                       Desk = controller.Desk,
                                       IsErroneous = false,
                                       IsSelected = false
                                   };

                    cell.AppearanceDefault.CopyFrom(AppearanceDefault);
                    cell.AppearanceError.CopyFrom(AppearanceError);
                    cell.AppearanceSelected.CopyFrom(AppearanceSelected);

                    cell.MouseClick += delegate {
                                           SelectCell(cell);
                                       };

                    cells[i, j] = cell;
                    Controls.Add((Control) cell);
                }
            }
        }

        private void SelectCell(ICellView cell) {
            if(errorCell != null){
                ClearError();
            }

            if(selectedCell != null){
                selectedCell.IsSelected = false;
            }

            selectedCell = cell;
            selectedCell.IsSelected = true;
        }

        private void ClearError() {
            if(errorCell == null)
                return;

            errorCell.IsErroneous = false;
            errorCell = null;
        }

        private Point GetCellCoordinates(ICellView cell) {
            for (int i = 0; i < 9; i++){
                for (int j = 0; j < 9; j++){
                    if (cells[i, j] == cell)
                        return new Point(i, j);
                }
            }
            throw new ArgumentException();
        }

        public void CellError(int rowIndex, int colIndex, IValue value) {
            errorCell = cells[rowIndex, colIndex];
            errorCell.ErrorValue = value.ToString();
            errorCell.IsErroneous = true;
        }

        #endregion

        #region Event handling routines

        private void SudokuView_KeyDown(object sender, KeyEventArgs e) {
            byte? num = null;
            bool suppress = false;

            ClearError();

            Point coords = GetCellCoordinates(selectedCell);

            if(!controller.CellIsFree(coords.X,coords.Y))
                return;

            if (e.KeyValue > 48 && e.KeyValue < 58) {
                num = (byte?) (e.KeyValue - 48);
            } else if (e.KeyValue > 96 && e.KeyValue < 106) {
                num = (byte?) (e.KeyValue - 96);
            } else if(e.KeyCode==Keys.Back) {
                suppress = true;
            }

            e.SuppressKeyPress = suppress || num.HasValue;
            e.Handled = e.SuppressKeyPress;
            if(e.SuppressKeyPress){
                controller.SetValue(coords.X, coords.Y, new UserValue(num));
                
            }
        }

        private void SudokuView_Paint(object sender, PaintEventArgs e) {
            var pen = new Pen(Brushes.Blue, 2);

            for (int i = 1; i < 3; i++){
                int coord = 6 + (i*3 - 1)*2 + 50*3*i;
                e.Graphics.DrawLine(pen, 5, coord, Width-5, coord);
                e.Graphics.DrawLine(pen, coord, 5, coord, Height-5);
            }

            pen.Dispose();
        }

        #endregion
    }
}